picoCTF Play Nice Write Up
Details:
Points: 110
Jeopardy style CTF
Category: Cryptography
Comments: Not all ancient ciphers were so bad... The flag is not in standard format. nc mercury.picoctf.net 30568 playfair.py
Write up:
Running the netcat command we get:
nc mercury.picoctf.net 30568
Here is the alphabet: 0fkdwu6rp8zvsnlj3iytxmeh72ca9bg5o41q
Here is the encrypted message: herfayo7oqxrz7jwxx15ie20p40u1i
What is the plaintext message?
Looking into the python script provided I first generated the matrix using the provided alphabet so that I had it to look at:
# [['0', 'f', 'k', 'd', 'w', 'u'],
# ['6', 'r', 'p', '8', 'z', 'v'],
# ['s', 'n', 'l', 'j', '3', 'i'],
# ['y', 't', 'x', 'm', 'e', 'h'],
# ['7', '2', 'c', 'a', '9', 'b'],
# ['g', '5', 'o', '4', '1', 'q']]
I then started slowing reversing what the encryption did. From the encryption I saw that for each character one was added so the length would be the same. But that every pair relied on each other so I would need to iterate through two at a time:
# decrypt string function
def decrypt_string(s, matrix):
# place to store result
result = ""
# Iterate through string two at a time
for i in range(0, len(s), 2):
# pass the pairs to the decrypt_pair function
result += decrypt_pair(s[i:i+2], matrix)
# return result
return result
Next I looked at the encrypt pair function. I then looked at how the different cases were encrypted, checked for those cases and then decrypted:
# decrypt each pair
def decrypt_pair(pair, matrix):
# get the indices in the matrix
p1 = get_index(pair[0], matrix)
p2 = get_index(pair[1], matrix)
# if the first index is the same
if p1[0] == p2[0]:
return matrix[p1[0]][(p1[1]-1)%SQUARE_SIZE]+matrix[p2[0]][(p2[1]-1)%SQUARE_SIZE]
# if the second index is the same
if p1[1] == p2[1]:
return matrix[(p1[0] - 1) % SQUARE_SIZE][p1[1]] + matrix[(p2[0] - 1) % SQUARE_SIZE][p2[1]]
# else
return matrix[p1[0]][p2[1]] + matrix[p2[0]][p1[1]]
This gave me the following script:
# alphabet for matrix
alphabet = "0fkdwu6rp8zvsnlj3iytxmeh72ca9bg5o41q"
# square size
SQUARE_SIZE = 6
def generate_square(alphabet):
assert len(alphabet) == pow(SQUARE_SIZE, 2)
matrix = []
for i, letter in enumerate(alphabet):
if i % SQUARE_SIZE == 0:
row = []
row.append(letter)
if i % SQUARE_SIZE == (SQUARE_SIZE - 1):
matrix.append(row)
return matrix
def get_index(letter, matrix):
for row in range(SQUARE_SIZE):
for col in range(SQUARE_SIZE):
if matrix[row][col] == letter:
return (row, col)
print("letter not found in matrix.")
exit()
# decrypt each pair
def decrypt_pair(pair, matrix):
# get the indices in the matrix
p1 = get_index(pair[0], matrix)
p2 = get_index(pair[1], matrix)
# if the first index is the same
if p1[0] == p2[0]:
return matrix[p1[0]][(p1[1]-1)%SQUARE_SIZE]+matrix[p2[0]][(p2[1]-1)%SQUARE_SIZE]
# if the second index is the same
if p1[1] == p2[1]:
return matrix[(p1[0] - 1) % SQUARE_SIZE][p1[1]] + matrix[(p2[0] - 1) % SQUARE_SIZE][p2[1]]
# else
return matrix[p1[0]][p2[1]] + matrix[p2[0]][p1[1]]
# decrypt string function
def decrypt_string(s, matrix):
# place to store result
result = ""
# Iterate through string two at a time
for i in range(0, len(s), 2):
# pass the pairs to the decrypt_pair function
result += decrypt_pair(s[i:i+2], matrix)
# return result
return result
# generate square
m = generate_square(alphabet)
# encrypted message
enc_msg = "herfayo7oqxrz7jwxx15ie20p40u1i"
# decrypt string
print(decrypt_string(enc_msg, m))
When run I got:
emf57mgc51tp693dtt4g3h7f8ouwq3
When put into the nc instance I got the flag:
nc mercury.picoctf.net 30568
Here is the alphabet: 0fkdwu6rp8zvsnlj3iytxmeh72ca9bg5o41q
Here is the encrypted message: herfayo7oqxrz7jwxx15ie20p40u1i
What is the plaintext message? emf57mgc51tp693dtt4g3h7f8ouwq3
Congratulations! Here's the flag: 007d0a696aaad7fb5ec21c7698e4f754